﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;

namespace Dwarf.Managed
{
    /// <summary>
    /// Settings taken from command line and input file.
    /// </summary>
    class Settings
    {
        /// <summary>
        /// Input & output files.
        /// </summary>
        private String inputFile;
        private String profileFile;
        private String resultFile;



        /// <summary>
        /// Short dwarf's description.
        /// </summary>
        private const String DWARF_NAME = "Combinational Logic, managed serial kernel.";

        /// <summary>
        /// Constants for output files's names
        /// </summary>
        private const String DWARF_NAME_OUTPUT = "Dwarf.Managed.Serial";
        private const String PROFILE_TXT = ".Profile.txt";
        private const String RESULT_TXT = ".Result.txt";

        /// <summary>
        /// Default size for buffer.
        /// </summary>
        private const int BUFFER_SIZE = 1024;

        /// <summary>
        /// Block for reading from file
        /// </summary>
        private const int MAX_BLOCK_SIZE = 1024 * 1024; //1 mb

        /// <summary>
        /// Constructor that init strings.
        /// </summary>
        public Settings()
        {
            inputFile = new String(new char[BUFFER_SIZE]);
            profileFile = new String(new char[BUFFER_SIZE]);
            resultFile = new String(new char[BUFFER_SIZE]);
        }

        /// <summary>
        /// Problem results output.
        /// </summary>
        /// <param name="clsolver">
        /// Instance of Solver.
        /// </param>
        public void Finish(Solver clsolver)
        {
            double time = 0; ;
            stop(ref time);

            Console.WriteLine();
            Console.WriteLine("Clock time (sec): {0} ", time.ToString("F8"));


                try
                {
                    using (StreamWriter outputResult = File.CreateText(resultFile))
                    {
                        using (StreamWriter outputProfile = File.CreateText(profileFile))
                        {
                            outputProfile.WriteLine("#Dwarfname:{0}", DWARF_NAME);

                            outputProfile.WriteLine("#Time: {0}", DateTime.Now.ToString());

                            outputProfile.WriteLine("#Result time (sec): {0}", time);
                            outputProfile.WriteLine("#File length (byte) : {0}", clsolver.length);
                            outputProfile.WriteLine("#Result count: {0}", clsolver.resultCount);
                            outputResult.WriteLine("#Result count: {0}", clsolver.resultCount);

                            outputProfile.WriteLine("#eof");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    throw new Exception("Error in output file");
                }
            

        }

        /// <summary>
        /// Init variables, parse cli params and input file.
        /// </summary>
        /// <param name="args">
        /// Cli params.
        /// </param>
        /// <param name="clsolver">
        /// Instance of Solver.
        /// </param>
        public void Init(String[] args, Solver clsolver)
        {
            //Parse cli params.
            parseArguments(
                         args.Length,
                         args,
                         ref inputFile,
                         ref profileFile,
                         ref resultFile);

            //Parse input file.
            parseConfigFile(clsolver);

            // write settings if it's needed
            WriteSettings(clsolver);
        }

        /// <summary>
        /// Start the time count.
        /// </summary>
        public void Start()
        {
            start();
        }

        /// <summary>
        /// Get one line from stream.
        /// </summary>
        /// <param name="clsolver">
        /// Stream to get from.
        /// </param>
        private static String GetLine(StreamReader sr)
        {
            String s = sr.ReadLine();

            //Avoid comments lines.
            while (s.StartsWith("#") || s.StartsWith("//"))
            {
                s = sr.ReadLine();
            }

            return s;
        }

        /// <summary>
        /// Parse input file into solver's structures.
        /// </summary>
        /// <param name="clsolver">
        /// Instance of Solver.
        /// </param>
        private void parseConfigFile(Solver clsolver)
        {
            
            try
            {
                // Open the file to read from.
                clsolver.input = new BinaryReader(new FileStream(inputFile, FileMode.Open, FileAccess.Read, FileShare.None, MAX_BLOCK_SIZE, true));

                //Get length of file.
                clsolver.length = (int)clsolver.input.BaseStream.Length;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                throw new Exception("Error in input file");
            }
        }

        /// <summary>
        /// Write settings.
        /// </summary>
        /// <param name="clsolver">
        /// Instance of Solver.
        /// </param>
        private void WriteSettings(Solver clsolver)
        {
            // Write general settings.
            Console.WriteLine("Kernel settings summary : ");
            Console.WriteLine("Dwarf name              : {0} ", DWARF_NAME);
            Console.WriteLine("File length (byte)      : {0} ", clsolver.length);
            Console.WriteLine("Inputfile               : {0} ", inputFile);
            Console.WriteLine("Profilefile             : {0} ", profileFile);
            Console.WriteLine("Resultfile              : {0} ", resultFile);
            Console.WriteLine();

        }

        [DllImport(@"CliTools.dll")]
        private static extern void parseArguments(
            int argc,
            String[] argv,
            ref string inputFile,
            ref string profileFile,
            ref string resultFile
            );

        [DllImport(@"CliTools.dll")]
        private static extern void start();

        [DllImport(@"CliTools.dll")]
        private static extern void stop(ref double time);
    }
}
